/*
** XSwarm
** ======
**
** Purpose:	Display a swarm of bees chasing a wasp.
**
** Features:	uses only integer math
**		has no redeeming social value
**
** Comments:	Most of this program is greatly rewritten by me, but the
**		initial math and update stuff is left over from the older
**		program.  Much of the NeXT related stuff is from LizardSaver.
**
** Created:	by Jeff Butterworth on 7/11/90
**		butterwo@cs.unc.edu
**
** NeXTPoRT:    Kurt Werle
**              frsvnsvn!kurt@crash.cts.com
**
** Updated:	by Kurt Werle on 10/28/91
**
*/

/* Standard Includes */
#import "Thinker.h"
#import <appkit/NXImage.h>
#import <appkit/Panel.h>                // for NXRunAlertPanel()
//#import <appkit/appkit.h>
#import <dpsclient/wraps.h>
#import <libc.h>
#import <math.h>

/* For those of you who want to know what version you are using. */

/* Includes for this project. */
#import "SwarmView.h"

@implementation SwarmView

- initFrame:(NXRect *)frameRect
{
	[super initFrame:frameRect];
	[self newSize];
	[NXApp loadNibSection:"SwarmPrefs.nib" owner:self];
	winNum=[[self window] windowNum];

	return self;
}

- sizeTo:(NXCoord)width :(NXCoord)height
{
	[super sizeTo:width :height];
	mywidth = width;
	myheight = height;
	return self;
}

- newSize
{
	int b;
	
	/* Get the random number generator ready. */
	srandom(getpid());
	
	times = TIMES;		/* number of time steps recorded  */
	newbees = bees = BEES;	/* number of bees */
	wasp_vel = WASPVEL;	/* maximum wasp speed */
	bee_vel = BEEVEL;	/* maximum bee speed */
	wasp_acc = WASPACC;	/* maximum wasp acceleration */
	bee_acc = BEEACC;	/* bee acceleration */
	timeout = 0;		/* time in seconds before screen saving */
	border = BORDER;	/* border limiting wasp travel */
	verbose = FALSE;	/* display settings if TRUE */
	stay_in_front = FALSE;	/* Try to stay in clear area of the screen. */
	root = FALSE;		/* display in root window */
	cursortime = 0;		/* Number of updates to follow the cursor */

	/*alloc the mem*/
	x = (int *) malloc(sizeof(int) * MAXBEES * times);
	y = (int *) malloc(sizeof(int) * MAXBEES * times);
	xv = (int *) malloc(sizeof(int) * MAXBEES);
	yv = (int *) malloc(sizeof(int) * MAXBEES);
	/* wasp */
	wx[0] = BORDER + random() % (int) (mywidth - 2*BORDER);
	wy[0] = BORDER + random() % (int) (myheight - 2*BORDER);
	wx[1] = wx[0];
	wy[1] = wy[0];
	wxv = 0;
	wyv = 0;

	/* set up bees */
	for (b = 0 ; b < MAXBEES ; b++)
	{
		X(0,b) = random() % 1000;   /* Fudge */
		/*X(0,b) = random() % mywidth;  Why can't I use this?*/
		X(1,b) = X(0,b);
		Y(0,b) = random() % 1000;   /* Fudge */
		/*Y(0,b) = random() % myheight; Why can't I use this?*/
		Y(1,b) = Y(0,b);
		xv[b] = RAND(7);
		yv[b] = RAND(7);
		/* Initialize point positions, velocities, etc. */

	}

	return self;
}

/* Animate()								*/
/* Move the swarm around.						*/

- oneStep
{
    int			b;		/* bee index */
    int			dx,dy,distance;

	bees = newbees;
    /* These variables are related to mouse control of the wasp. */



	/* <=- Wasp -=> */
	/* Age the position arrays. */
	wx[2] = wx[1];
	wx[1] = wx[0];
	wy[2] = wy[1];
	wy[1] = wy[0];
	
	PScurrentmouse(winNum, &curX, &curY);

	if (cursortime)   /* If there's time left on the cursor count */
		{
		wx[0] = (int) curX;   wy[0] = (int) curY;
		}
	else
		{
			
		/* Accelerate */
		wxv += RAND(wasp_acc);
		wyv += RAND(wasp_acc);
		/* Speed Limit Checks */
		if (wxv > wasp_vel) wxv = wasp_vel;
		if (wxv < -wasp_vel) wxv = -wasp_vel;
		if (wyv > wasp_vel) wyv = wasp_vel;
		if (wyv < -wasp_vel) wyv = -wasp_vel;

		/* Move */
		wx[0] = wx[1] + wxv;
		wy[0] = wy[1] + wyv;

		/*	     Bounce Checks */
		if ((wx[0] < border))
			{
			wxv = abs(wxv);
			}
		if ((wy[0] < border))
			{
			wyv = abs(wyv);
			}
		if ((wx[0] > mywidth-border-1))
			{
			wxv = -(abs(wxv));
			}
		if ((wy[0] > myheight-border-1))
			{
			wyv = -(abs(wyv));
			}
		}
	/* Test the cursor */
	if (mywidth - curX + myheight - curY <= 10.0)
		[self show]; 

	/* Don't let things settle down. */
	xv[random() % bees] += RAND(3);
	yv[random() % bees] += RAND(3);

	/* <=- Bees -=> */
	for (b = 0 ; b < bees ; b++)
	{
	    /* Age the arrays. */
	    X(2,b) = X(1,b);
	    X(1,b) = X(0,b);
	    Y(2,b) = Y(1,b);
	    Y(1,b) = Y(0,b);

	    /* Accelerate */
	    dx = wx[1] - X(1,b);
	    dy = wy[1] - Y(1,b);
	    distance = abs(dx)+abs(dy); /* approximation */
	    if (distance == 0) distance = 1;
	    xv[b] += (dx*bee_acc)/distance;
	    yv[b] += (dy*bee_acc)/distance;

	    /* Speed Limit Checks */
	    if (xv[b] > bee_vel) xv[b] = bee_vel;
	    if (xv[b] < -bee_vel) xv[b] = -bee_vel;
	    if (yv[b] > bee_vel) yv[b] = bee_vel;
	    if (yv[b] < -bee_vel) yv[b] = -bee_vel;

	    /* Move */
	    X(0,b) = X(1,b) + xv[b];
	    Y(0,b) = Y(1,b) + yv[b];
	    

	}

	/* Erase previous, draw current, sync for smoothness. */


	/* Draw Wasp */
	if (1)
	{
		/*NXRect myrect = {0, 0, mywidth, myheight};
		PSsetgray(0);
		NXRectFill(&myrect);*/

		PSsetgray(1.0);
 		PSmoveto(wx[0], wy[0]); 
		PSlineto(wx[1], wy[1]);
  		PSstroke();
		/**/PSsetgray(0.0);
		PSmoveto(wx[1], wy[1]);
		PSlineto(wx[2], wy[2]);
  		PSstroke();/**/
	}

	/* Draw Bees */
	{
		PSsetgray(1.0);
		for (b = 0 ; b < bees ; b++)
		{
 			PSmoveto(X(0,b), Y(0,b)); 
			PSlineto(X(1,b), Y(1,b));
		}
  		PSstroke();
		PSsetgray(0.0);
		for (b = 0 ; b < bees ; b++)
		{
			PSmoveto(X(1,b), Y(1,b));
			PSlineto(X(2,b), Y(2,b));
		}
  		PSstroke();/**/

	}
	return self;
	
}
- (BOOL) useBufferedWindow
{	return NO;
}
- show
	{
	[myPrefWindow orderFront:nil];
	return self;
	}
- setNumberBees: sender
	{
	NXRect aRect = {0, 0, mywidth, myheight};
	newbees = [sender intValue];
	[beeText takeIntValueFrom:sender];
	[self lockFocus];
	PSsetgray(0.0);
	NXRectFill(&aRect);
	[self unlockFocus];
	return self;
	}
- setFollow: sender
	{	
	cursortime = [sender intValue];
	return self;
	}
@end

